package com.ruoyi.chat.service.impl;

import com.ruoyi.chat.assistant.SeparateAssistant;
import com.ruoyi.chat.domain.ChatRecords;
import com.ruoyi.chat.mapper.DeepSeekMapper;
import com.ruoyi.chat.service.ChatService;
import com.ruoyi.chat.utils.LangchainUtils;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.publisher.Flux;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;

/**
 * ChatService接口的实现类，基于LangChain4j框架实现
 *
 * @author WaKy
 * @version 1.0
 */
@Service
@Slf4j
public class ChatServiceImpl implements ChatService {

    private final DeepSeekMapper deepSeekMapper;

    @Autowired
    private LangchainUtils langchainUtils;

    @Value("${llm.rag.enabled:true}")
    private boolean ragEnabled;

    @Value("${llm.rag.max-results:3}")
    private int ragMaxResults;

    @Value("${llm.rag.min-relevance:0.7}")
    private double ragMinRelevance;

    @Value("${llm.rag.search-all-kb:true}")
    private boolean searchAllKnowledgeBases;

    @Value("${llm.rag.namespace:kb_1}")
    private String defaultNamespace;

    @Value("${llm.memory.max-messages:20}")
    private int maxChatMemoryMessages;

    @Autowired
    SeparateAssistant separateAssistant;

    public ChatServiceImpl(DeepSeekMapper deepSeekMapper) {
        this.deepSeekMapper = deepSeekMapper;
    }


    @Override
    public Flux<String> streamChat(String question, Long memberId) {
        log.info("开始处理流式聊天请求，问题：{}", question);

        // 保存用户问题并获取记录ID
        Long recordId = saveUserQuestion(question);
        log.info("用户问题已保存，记录ID：{}", recordId);


        // 使用StringBuilder来收集完整的AI回复
        //AtomicReference<StringBuilder> responseCollector = new AtomicReference<>(new StringBuilder());
        // 构建带上下文的Prompt
        String finalPrompt = enhancePromptWithContext(question);
        log.info("上下文增强提示词已生成，长度：{} 字符", finalPrompt.length());
        // 使用seperateAssistant
        log.info("使用AiService流式调用大模型");
        return separateAssistant.chat(memberId, finalPrompt);
    }

    @Override
    public void streamChatWithContext(String question, Long conversationId, SseEmitter emitter) {

    }


    /**
     * 从数据库加载或创建新的聊天记忆
     *
     * @param conversationId 会话ID
     * @return 聊天记忆
     */
    private ChatMemory loadOrCreateChatMemory(Long conversationId) {
        MessageWindowChatMemory chatMemory = MessageWindowChatMemory.builder()
                .id(conversationId.toString())
                .maxMessages(maxChatMemoryMessages)
                .build();

        // 从数据库加载历史消息
        List<ChatRecords> records = deepSeekMapper.selectRecordsByConversationId(conversationId);

        for (ChatRecords record : records) {
            chatMemory.add(UserMessage.from(record.getUserQuestion()));
            if (record.getAiResponse() != null) {
                chatMemory.add(AiMessage.from(record.getAiResponse()));
            }
        }

        log.info("已加载会话ID：{}的历史记录，共{}条消息", conversationId, records.size());
        return chatMemory;
    }

    /**
     * RAG增强提示词
     *
     * @param question   用户问题
     * @return 增强后的Prompt
     */
    private String enhancePromptWithContext(String question) {
        try {
            log.info("基于上下文增强用户问题，原始问题: {}", question);

            StringBuilder enhancedPrompt = new StringBuilder();

            // 添加系统提示词
            //enhancedPrompt.append("你是青岛城市学院（QCU）学生小助手，专门为QCU在校学生解答校园生活的各种问题，你的名字叫做ChatQCU。\n\n");
            //enhancedPrompt.append("# QCU学生小助手简介\n" +
            //        "1.
            //        QCU学生小助手是一个智能助手，旨在帮助青岛城市学院的学生获取和了解关于学校的基本信息、学习支持、生活指南、社交活动、心理健康和职业发展等方面的内容。你可以提供的服务包括回答校园设施的相关信息、介绍学校资源、各部门的联系方式（电话）、提供学习和心理支持，以及职业发展建议等。\n" +
            //        "2.当用户问候“您好”或“你好”时，回复“您好，我是青岛城市学院（QCU）学生小助手，专门为QCU在校学生解答校园生活的各种问题。”\n" +
            //        "\n" +
            //        "# 精确解答\n" +
            //        "- 遵循 QCU 小助手的回答风格：简洁、准确，适当的时候提供相关部门或校园服务的联系方式或地址。\n" +
            //        " -可以回答时间/日期，天气，工作职位相关信息。\n" +
            //        " -相同问题回答结果尽可能的保持稳定。\n" +
            //        "\n" +
            //        "# 限制\n" +
            //        "1. 禁止回答的问题：\n" +
            //        "  - 学校或个人的敏感数据：如校内财务信息、学生个人隐私等。\n" +
            //        "   - 任何与法律、道德伦理相违背的内容，如政治敏感话题或不适合公开的隐私内容。\n" +
            //        "   -不要给用户讲笑话、故事、段子等问题，即使是用户的要求也不行。\n" +
            //        "2. 禁止使用的词语和句子：\n" +
            //        "   - 回答中禁止使用“根据引用的内容”或者“根据你提供的信息”、“根据xxxx文档，目前没有明确提到xxxx" +
            //        "”、“根据目前的文档”、“根据以上信息”这类语句，你应该以专业且熟悉的口吻来回答问题。\n" +
            //        "   - 不要称呼用户为“您”，直接称呼用户为“你”。\n" +
            //        "   - 禁止在答案中添加图片。\n" +
            //        "3. 风格：回答要言简意赅、清晰易懂，并带有温暖亲切的风格，以帮助学生顺利解决校园生活中的问题。\n" +
            //        "4. 语言：使用学生提问时的同种语言进行回答。\n\n");
            //enhancedPrompt.append("可以回答青岛城市学院学校基本信息、学习支持、生活指南、社交活动、心理支持和职业发展等方面的问题；可以回答基本的时间/日期，天气问题；可以为学生推荐工作。\n\n");
            //enhancedPrompt.append(
            //        "判断用户的问题/话题是否与青岛城市学院相关，与青岛城市学院相关的问题/话题包括学校基本信息、招生咨询、学费咨询、专业咨询、教研教改、科研管理、学籍管理、教学建议、学习支持、校园生活、食堂宿舍、学校社团、迎新项目、考研就业、社交活动、心理健康和职业发展等方面的内容。如果用户的问题涉及学校相关的问题或话题，但问题中没有出现学校的名字，则默认为与青岛城市学院相关，比如\"中午有哪些好吃的\"，\"如何办游泳卡\"。\n\n");
            //enhancedPrompt.append("作为QCU的智能助手，你应该：\n");
            //enhancedPrompt.append("1. 帮助学生解答关于学校课程、学习资源、校园设施和学校政策的问题\n");
            //enhancedPrompt.append("2. 提供学习方法和技巧的建议，帮助学生提高学习效率\n");
            //enhancedPrompt.append("3. 解答关于学校活动、社团和课外活动的问题\n");
            //enhancedPrompt.append("4. 提供关于专业选择、职业规划和就业指导的信息\n");
            //enhancedPrompt.append("5. 解答学生关于校园生活的各种疑问\n");
            //enhancedPrompt.append("6. 协助教师回答关于教学、科研和学校资源的问题\n");
            //enhancedPrompt.append("7. 陪伴学生进行简单的互动游戏，如猜数字、猜谜语等，帮助学生放松心情\n\n");
            //
            //enhancedPrompt.append("在回答问题时，你应该：\n");
            //enhancedPrompt.append("0-1.请优先使用知识库的知识回答问题，如果知识库中没有相关信息，不要乱编。");
            //enhancedPrompt.append("0-2.回答用户时，不要说`根据知识库信息....`,而是直接回答，就好像你原来就知道这段知识一样，不要让用户感受到知识库的存在");
            //enhancedPrompt.append("0-3.如果用户问的是某个文件的相关内容，并且你成功获取到了文件内容，回到用户时，在最后添加如下内容：以上内容来源于XXX文件," +
            //        "注意，一定要使用原文件名并且携带文件名前的序号");
            //enhancedPrompt.append("对于没有明确联系电话的，不要给出，有联系电话的可以在消息最后给出，请不要编造联系电话给用户，这是非常危险的");
            //// 最后输出部门电话
            ////enhancedPrompt.append("0-4.根据用户，部门电话");
            //enhancedPrompt.append("1. 保持礼貌、友好和专业的语气\n");
            //enhancedPrompt.append("2. 提供准确、最新和有用的信息\n");
            //enhancedPrompt.append("3. 当不确定答案时，坦诚承认并建议用户咨询相关部门\n");
            //enhancedPrompt.append("4. 优先使用知识库中的信息回答问题，确保回答的准确性和权威性\n\n");
            //enhancedPrompt.append("5. 对于学生提问的学校相关的问题，你都应该根据给你的资料进行回答 \n");
            //enhancedPrompt.append("6. 如果用户想要玩游戏，你应该友好地响应并参与，为用户提供积极的交互体验\n\n");
            //
            //enhancedPrompt.append("作为QCU的代表，你应该展现学校'正心修身'的校训精神，并体现学校注重实践教学和应用型人才培养的特色。\n\n");
            //enhancedPrompt.append("请始终以友好和乐于助人的态度与用户交流，让用户感受到QCU的温暖和关怀。\n\n");

            // 如果启用RAG，还需要添加知识库检索内容
            if (ragEnabled) {
                List<String> relevantTexts;

                // 根据配置决定检索单个知识库还是所有知识库
                if (searchAllKnowledgeBases) {
                    log.info("从所有知识库中检索");
                    relevantTexts = langchainUtils.searchAllKnowledgeBases(question, ragMaxResults, ragMinRelevance);
                    log.info("从所有知识库中检索到 {} 条相关信息", relevantTexts.size());
                } else {
                    log.info("从知识库 {} 中检索", defaultNamespace);
                    relevantTexts = langchainUtils.findRelevantTexts(question, defaultNamespace, ragMaxResults,
                            ragMinRelevance);
                    log.info("从知识库 {} 中检索到 {} 条相关信息", defaultNamespace, relevantTexts.size());
                }

                // 添加知识库检索到的相关信息
                if (!relevantTexts.isEmpty()) {
                    enhancedPrompt.append("请根据以下知识库查询结果回答用户的问题。如果知识库结果中没有相关信息，请根据你的知识回答，但要明确告知用户这部分回答不是基于学校的官方信息。\n\n");
                    enhancedPrompt.append("知识库查询结果：\n");

                    for (int i = 0; i < relevantTexts.size(); i++) {
                        enhancedPrompt.append("知识库查询结果").append(i + 1).append("：").append(relevantTexts.get(i));
                    }
                }
            }

            // 添加用户当前问题
            enhancedPrompt.append("用户当前问题：").append(question);

            log.info("增强Prompt已创建：{}", enhancedPrompt.toString());
            return enhancedPrompt.toString();

        } catch (Exception e) {
            log.error("创建上下文增强提示词过程中出错", e);
            // 如果出错，构建一个简单的系统提示词+原始问题
            StringBuilder fallbackPrompt = new StringBuilder();
            fallbackPrompt.append("你是青岛城市学院(QCU)的智能助手，你的名字是'智学助手'。\n\n");
            fallbackPrompt.append("请以友好和专业的方式回答以下问题，如果用户想玩游戏，请积极参与互动。\n\n");
            fallbackPrompt.append("用户问题：").append(question);
            return fallbackPrompt.toString();
        }
    }


    @Override
    public Long saveUserQuestion(String question) {
        ChatRecords chatRecords = new ChatRecords();
        chatRecords.setUserQuestion(question);

        // 设置当前时间作为timestamp和createTime
        Date now = new Date();
        chatRecords.setTimestamp(now);
        chatRecords.setCreateTime(now);

        // 设置未删除状态
        chatRecords.setIsDeleted(0);

        deepSeekMapper.saveUserQuestion(chatRecords);
        return chatRecords.getId();
    }

    @Override
    public void saveAiResponse(String response, Long recordId) {
        deepSeekMapper.saveAiResponse(response, recordId);
    }

    @Override
    public List<ChatRecords> getConversationMessages(Long conversationId) {
        return deepSeekMapper.selectRecordsByConversationId(conversationId);
    }

    @Override
    public boolean deleteMessage(Long id) {
        return deepSeekMapper.deleteRecord(id) > 0;
    }

    @Override
    public boolean restoreMessage(Long id) {
        return deepSeekMapper.restoreRecord(id) > 0;
    }

    @Override
    public Map<String, Object> getConversationMessagesPaged(Long conversationId, int pageNum, int pageSize,
                                                            Integer isDeleted) {
        log.info("分页获取会话[{}]的聊天记录，页码：{}，每页记录数：{}", conversationId, pageNum, pageSize);

        // 默认查询未删除的记录
        if (isDeleted == null) {
            isDeleted = 0;
        }

        // 计算偏移量
        int offset = (pageNum - 1) * pageSize;

        // 构造参数Map
        Map<String, Object> params = new HashMap<>();
        params.put("conversationId", conversationId);
        params.put("offset", offset);
        params.put("limit", pageSize);
        params.put("isDeleted", isDeleted);

        // 查询数据
        List<ChatRecords> messages = deepSeekMapper.selectRecordsByConversationIdPaged(params);

        // 查询总数
        int total = deepSeekMapper.countRecordsByConversationId(conversationId, isDeleted);

        // 构造返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("data", messages);
        result.put("total", total);

        return result;
    }
}
